

#include "../byteorder.hpp"

#include <cstring>
#include <string>
#include <vector>
#include <bits/char_traits.h>

#include <boost/operators.hpp>
#include <boost/asio/buffer.hpp>

namespace xbase
{
	//
	// wrapper_cast - cast data to be wrapper pointer
	//
	
	template<typename WrapperPointer>
	static inline
	WrapperPointer wrapper_cast(void *p_data) {
		return reinterpret_cast<WrapperPointer>(p_data);
	}
	
	template<typename ConstWrapperPointer>
	static inline
	ConstWrapperPointer wrapper_cast(const void *p_data) {
		return reinterpret_cast<ConstWrapperPointer>(p_data);
	}

	template<typename WrapperPointer>
	static inline
	WrapperPointer wrapper_cast(const boost::asio::mutable_buffer &p_data) {
		return reinterpret_cast<WrapperPointer>(boost::asio::buffer_cast<char*>(p_data));
	}
	
	template<typename ConstWrapperPointer>
	static inline
	ConstWrapperPointer wrapper_cast(const boost::asio::const_buffer &p_data) {
		return reinterpret_cast<ConstWrapperPointer>(boost::asio::buffer_cast<const char*>(p_data));
	}
	
	//
	// integer_wrapper - wrapper for char, short, int, long, long
	// long, both signed and unsigend
	// 
	template<typename Integer,
		 typename ByteOrder>
	struct integer_wrapper
		// : public boost::integer_arithmetic< integer_wrapper<Integer, ByteOrder>,
		// 				    boost::integer_arithmetic<integer_wrapper<Integer, ByteOrder>, Integer,
		// 							      boost::less_than_comparable< integer_wrapper<Integer, ByteOrder>,
		// 											   boost::less_than_comparable<integer_wrapper<Integer, ByteOrder>, Integer
		// 														       boost::equality_comparable<integer_wrapper<Integer, ByteOrder>,
		// 																		  boost::equality_comparable<integer_wrapper<Integer, ByteOrder>, Integer>
		// 																		  >
		// 														       >
		// 											   >
		// 							      >
		// 				    >
	{
		// 
		// traits
		//
		//#include <boost/static_assert.hpp>
		//#include <boost/type_traits.hpp>
		//BOOST_STATIC_ASSERT(boost::is_integral<Integer>::value);
		typedef Integer value_type;
		typedef ByteOrder byteorder;

		typedef integer_wrapper<Integer, ByteOrder> this_type;

		enum
		{
			MINIMAL_BYTES = sizeof(Integer)
		};

		// 
		// data field
		//
		
		//value_type m_integer;
		char m_integer[sizeof(value_type) / sizeof(char)];

		//
		// ops
		//

		integer_wrapper(value_type n = value_type(0)) {
			set(n);
		}

		integer_wrapper(const this_type &other) {
			*reinterpret_cast<value_type*>(m_integer) = *reinterpret_cast<const value_type*>(other.m_integer);
		}

		this_type &operator=(value_type n) {
			set(n);
			return *this;
		}

		this_type &operator=(const this_type &other) {
			if(this != &other)
			{
				*reinterpret_cast<value_type*>(m_integer)
					= *reinterpret_cast<const value_type*>(other.m_integer);
			}
			return *this;
		}
		
		value_type get() const {
			//return kb::get_integer<byteorder, value_type>(m_integer);
			return kb::from_byteorder_cast<byteorder>(*reinterpret_cast<const value_type*>(m_integer));
		}

		void set(const value_type &p_integer) {
			//kb::put_integer<byteorder, value_type>(m_integer, p_integer);
			*reinterpret_cast<value_type*>(m_integer) = kb::to_byteorder_cast<byteorder>(p_integer);
		}

		void clear() {
			set(value_type(0));
		}

		size_t bytes() const {
			return sizeof(m_integer);
		}

		// 
		// operators
		// 

		// this_type &operator+=(value_type n) {
		// 	set(get() + n);
		// 	return *this;
		// }

		// this_type &operator+=(const this_type &other) {
		// 	set(get() + other.get());
		// 	return *this;
		// }

		// this_type &operator-=(value_type n) {
		// 	set(get() - n);
		// 	return *this;
		// }

		// this_type &operator-=(const this_type &other) {
		// 	set(get() - other.get());
		// 	return *this;
		// }

		// 相等比较不需要转换字节序
		inline
		bool operator==(const this_type &other) const {
			return (*reinterpret_cast<const value_type*>(m_integer))
				== (*reinterpret_cast<const value_type*>(other.m_integer));
		}

		inline
		bool operator!=(const this_type &other) const {
			return ! this->operator==(other);
		}
	};

	template<typename Integer,
		 typename Elem,
		 typename ByteOrder>
	struct array_wrapper
		: public boost::less_than_comparable< array_wrapper<Integer, Elem, ByteOrder>,
						      boost::equality_comparable< array_wrapper<Integer, Elem, ByteOrder> > >
	{
		// 
		// traits
		//
		
		typedef Integer size_type;
		typedef Elem value_type;
		typedef ByteOrder byteorder;

		// 
		// data field
		//
		
		integer_wrapper<Integer, byteorder> m_size;

		enum
		{
			MINIMAL_BYTES = integer_wrapper<Integer, byteorder>::MINIMAL_BYTES,
			POS_DATA = sizeof(Integer)
		};

		// 
		// ops
		// 

		bool empty() const {
			return m_size.get() == 0;
		}

		size_type size() const {
			return m_size.get();
		}

		void set_size(size_type p_size) {
			m_size.set(p_size);
		}

		const value_type *data() const {
			return reinterpret_cast<const Elem *>(reinterpret_cast<const char *>(this) + POS_DATA);
		}

		value_type *data() {
			return reinterpret_cast<Elem *>(reinterpret_cast<char *>(this) + POS_DATA);
		}

		size_t bytes() const {
			return size() * sizeof(value_type) + sizeof(size_type);
		}

		void clear() {
			m_size.clear();
		}

		void fill(const value_type *p_data, size_type p_size) {
			std::memcpy(this->data(),
				    p_data,
				    p_size * sizeof(value_type));
			this->set_size(p_size);
		}

		template<typename Alloc>
		void fill(const std::vector<value_type, Alloc> &p_vector) {
			std::memcpy(this->data(),
				    &p_vector[0],
				    p_vector.size() * sizeof(value_type));
			this->set_size(p_vector.size());
		}

		template<typename Alloc>
		std::vector<value_type, Alloc> to_vector() const {
			return std::vector<value_type, Alloc>(this->data(),
							      this->data() + this->size());
		}
	};

	template<typename Integer,
		 typename Elem,
		 typename ByteOrder>
	static inline
	bool operator<(const array_wrapper<Integer, Elem, ByteOrder> &first,
		       const array_wrapper<Integer, Elem, ByteOrder> &second)
	{
		return (&first != &second) &&
			std::lexicographical_compare(first.data(), first.data() + first.size(),
						     second.data(), second.data() + second.size());
	}
	
	template<typename Integer,
		 typename Elem,
		 typename ByteOrder>
	static inline
	bool operator==(const array_wrapper<Integer, Elem, ByteOrder> &first,
			const array_wrapper<Integer, Elem, ByteOrder> &second)
	{
		return ((&first == &second) // just one object or
			|| ((first.size() == second.size()) // length equal and
			    && (std::equal(first.data(), first.data() + first.size(), // every element equal
					   second.data()))));
	}
	
	template<typename Integer,
		 typename Char,
		 typename ByteOrder,
		 typename Traits = std::char_traits<Char> >
	struct string_wrapper
		: public boost::less_than_comparable< string_wrapper<Integer, Char, ByteOrder>,
						      boost::equality_comparable< string_wrapper<Integer, Char, ByteOrder> > >
	{
		// 
		// traits
		//
		
		typedef Integer size_type;
		typedef Char char_type;
		typedef ByteOrder byteorder;
		typedef Traits traits_type;
		
		typedef string_wrapper<Integer, Char, ByteOrder, Traits> this_type;
		
		// 
		// data field
		//
		
		integer_wrapper<size_type, byteorder> m_size;
		
		enum
		{
			MINIMAL_BYTES = integer_wrapper<Integer, byteorder>::MINIMAL_BYTES,
			POS_DATA = sizeof(Integer)
		};
		
		//
		// ops
		// 
		
		bool empty() const {
			return m_size.get() == 0;
		}
		
		size_type size() const {
			return m_size.get();
		}
		
		void set_size(size_type p_size) {
			m_size.set(p_size);
		}
		
		const char_type *data() const {
			return reinterpret_cast<const char_type *>(reinterpret_cast<const char *>(this) + POS_DATA);
		}
		
		char_type *data() {
			return reinterpret_cast<char_type *>(reinterpret_cast<char *>(this) + POS_DATA);
		}
		
		size_t bytes() const {
			return size() * sizeof(char_type) + sizeof(size_type);
		}
		
		void clear() {
			m_size.clear();
		}
		
		// 
		// additional ops
		//
		
		template<typename Alloc>
		std::basic_string<char_type, traits_type, Alloc> to_string() const {
			return std::basic_string<char_type, traits_type, Alloc>(this->data(), this->size());
		}
		
		template<typename Alloc>
		operator std::basic_string<char_type, traits_type, Alloc> () const {
			return std::basic_string<char_type, traits_type, Alloc>(this->data(), this->size());
		}
		
		void fill(const char_type *p_data, size_type p_size) {
			std::memcpy(this->data(),
				    p_data,
				    p_size * sizeof(char_type));
			this->set_size(p_size);
		}

		void fill(const this_type &other) {
			fill(other.data(), other.size());
		}
		
		template<typename Alloc>
		void fill(const std::basic_string<char_type, traits_type, Alloc> &p_string) {
			p_string.copy(this->data(), p_string.size());
			this->set_size(p_string.size());
		}

		inline
		int compare(const this_type &other) const {
			return compare(other.data(), other.size());
		}

		template<typename Alloc>
		inline
		int compare(const std::basic_string<char_type, traits_type, Alloc> &p_string) const {
			return compare(p_string.data(), p_string.size());
		}

		inline
		int compare(const char_type *data, const size_type size) const {
			return compare(this->data(), this->size(),
				       data, size);
		}

		static inline
		int compare(const char_type *data1, const size_type size1,
			    const char_type *data2, const size_type size2) {
			const size_type min_size = (std::min)(size1, size2);
			const int cmp_ret = traits_type::compare(data1,
								 data2,
								 min_size);
			return (cmp_ret != 0) // 不相等，则直接返回比较结果；否则需要根据长度来决定
				? cmp_ret
				: (size1 < size2 // 长度小，则小
				   ? -1
				   : (size1 > size2 // 长度大，则大
				      ? 1
				      : 0)); // 长度相等，则相等
		}
	};
	
	template<typename Integer,
		 typename Char,
		 typename ByteOrder,
		 typename Traits>
	static inline
	bool operator<(const string_wrapper<Integer, Char, ByteOrder, Traits> &first,
		       const string_wrapper<Integer, Char, ByteOrder, Traits> &second)
	{
		return (&first != &second) &&
			string_wrapper<Integer, Char, ByteOrder, Traits>::compare(first.data(), first.size(),
										  second.data(), second.size()) < 0;
	}
	
	template<typename Integer,
		 typename Char,
		 typename ByteOrder,
		 typename Traits>
	static inline
	bool operator==(const string_wrapper<Integer, Char, ByteOrder, Traits> &first,
			const string_wrapper<Integer, Char, ByteOrder, Traits> &second)
	{
		const typename string_wrapper<Integer, Char, ByteOrder, Traits>::size_type size = first.size();
		return ((&first == &second) // just one object or
			|| ((size == second.size()) // length equal and
			    && (string_wrapper<Integer, Char, ByteOrder, Traits>::traits_type::compare(first.data(),
												       second.data(),
												       size) == 0)));
	}

	// 
	// compare to std::basic_string<> 
	// 

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator<(const std::basic_string<Char, Traits, Alloc> &first,
		       const xbase::string_wrapper<Size, Char, ByteOrder, Traits> &second)
	{
		return xbase::string_wrapper<Size, Char, ByteOrder, Traits>::compare(first.data(), first.size(),
										     second.data(), second.size()) < 0;
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator<(const xbase::string_wrapper<Size, Char, ByteOrder, Traits> &first,
		       const std::basic_string<Char, Traits, Alloc> &second)
	{
		return xbase::string_wrapper<Size, Char, ByteOrder, Traits>::compare(first.data(), first.size(),
										     second.data(), second.size()) < 0;
	}
	
	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator==(const std::basic_string<Char, Traits, Alloc> &first,
			const xbase::string_wrapper<Size, Char, ByteOrder, Traits> &second)
	{
		return ((first.size() == second.size())
			&& (Traits::compare(first.data(),
					    second.data(),
					    first.size()) == 0));
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator==(const xbase::string_wrapper<Size, Char, ByteOrder> &first,
			const std::basic_string<Char, Traits, Alloc> &second)
	{
		return second == first;
	}

	// others

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator>(const std::basic_string<Char, Traits, Alloc> &first,
		       const xbase::string_wrapper<Size, Char, ByteOrder> &second)
	{
		return (second < first);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator>(const xbase::string_wrapper<Size, Char, ByteOrder> &first,
		       const std::basic_string<Char, Traits, Alloc> &second)
	{
		return (second < first);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator<=(const std::basic_string<Char, Traits, Alloc> &first,
			const xbase::string_wrapper<Size, Char, ByteOrder> &second)
	{
		return ! (second < first);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator<=(const xbase::string_wrapper<Size, Char, ByteOrder> &first,
			const std::basic_string<Char, Traits, Alloc> &second)
	{
		return ! (second < first);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator>=(const std::basic_string<Char, Traits, Alloc> &first,
			const xbase::string_wrapper<Size, Char, ByteOrder> &second)
	{
		return ! (first < second);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator>=(const xbase::string_wrapper<Size, Char, ByteOrder> &first,
			const std::basic_string<Char, Traits, Alloc> &second)
	{
		return ! (first < second);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator!=(const std::basic_string<Char, Traits, Alloc> &first,
			const xbase::string_wrapper<Size, Char, ByteOrder> &second)
	{
		return ! (first == second);
	}

	template< typename Size,
		  typename Char,
		  typename Traits,
		  typename Alloc,
		  typename ByteOrder >
	static inline
	bool operator!=(const xbase::string_wrapper<Size, Char, ByteOrder> &first,
			const std::basic_string<Char, Traits, Alloc> &second)
	{
		return ! (first == second);
	}

} // namespace xbase
